home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / dialer.c < prev    next >
C/C++ Source or Header  |  1994-11-03  |  32KB  |  1,376 lines

  1. /* Automatic SLIP/PPP line dialer.
  2.  *
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  *    Mar '91    Bill Simpson & Glenn McGregor
  6.  *        completely re-written;
  7.  *        human readable control file;
  8.  *        includes wait for string, and speed sense;
  9.  *        dials immediately when invoked.
  10.  *    May '91 Bill Simpson
  11.  *        re-ordered command line;
  12.  *        allow dial only;
  13.  *        allow inactivity timeout without ping.
  14.  *    Sep '91 Bill Simpson
  15.  *        Check known DTR & RSLD state for redial decision
  16.  *    11 Mar 92 Giles Todd
  17.  *        Add "configure:" and "execute:" sections and new commands.
  18.  *    19 Mar 92 Giles Todd
  19.  *        Fix failure string processing.
  20.  *    31 May 92 Giles Todd
  21.  *        Fix empty configure string problems.
  22.  *    02 Jun 92 Giles Todd
  23.  *        Fix dial session cancel bug.
  24.  *
  25.  $Id: dialer.c 1.13 94/01/04 14:09:02 ROOT_DOS Exp $
  26.  *
  27.  *    04 Aug 92    1.6    GT    No change.
  28.  *    09 Aug 92    1.7    GT    Inline dialing.
  29.  *    17 Aug 92    1.8    GT    Allow escape from inline dial.
  30.  *    13 Sep 92    1.9    CMS    Ignore script lines consisting only of a newline.
  31.  *    03 Apr 93    1.11    GT    Fix order of calls.
  32.  *    08 May 93    1.12    GT    Fix warnings.
  33.  *                            Improve dialer interruption.
  34.  *    10 Dec 93    1.13    GT    Don't obscure modem messages.
  35.  *
  36.  * ATARI version by David Nash - dnash@chaos.demon.co.uk
  37.  *
  38.  *        Include st_asy.h in place of 8250.h
  39.  *
  40.  * 04.11.94 DFN dodial_status correct call to iostatus function
  41.  *
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include <string.h>
  47. #include "global.h"
  48. #include "config.h"
  49. #include "mbuf.h"
  50. #include "timer.h"
  51. #include "proc.h"
  52. #include "iface.h"
  53. #include "netuser.h"
  54. #ifdef ATARI
  55. #include "st_asy.h"
  56. #else
  57. #include "8250.h"
  58. #endif
  59. #include "asy.h"
  60. #include "tty.h"
  61. #include "session.h"
  62. #include "socket.h"
  63. #include "cmdparse.h"
  64. #include "devparam.h"
  65. #include "icmp.h"
  66. #include "files.h"
  67. #include "main.h"
  68. #include "trace.h"
  69. #include "hardware.h"
  70. #include "commands.h"
  71.  
  72. extern struct cmds far Cmds[];
  73.  
  74. #define MIN_INTERVAL    5L
  75.  
  76. typedef struct item ITEM;
  77.  
  78. struct item
  79.     {
  80.     char *data;                            /* some text                        */
  81.     ITEM *next;                            /* -> next in list                    */
  82.     };
  83.  
  84.  
  85. static int redial __ARGS((struct iface *ifp, char *file));
  86.  
  87. static int cfg_init            __ARGS((int argc, char *argv[], void *p));
  88. static int cfg_dial_cmd        __ARGS((int argc, char *argv[], void *p));
  89. static int cfg_ld_code        __ARGS((int argc, char *argv[], void *p));
  90. static int cfg_number        __ARGS((int argc, char *argv[], void *p));
  91. static int cfg_retries        __ARGS((int argc, char *argv[], void *p));
  92.  
  93. static int dodial_control    __ARGS((int argc, char *argv[], void *p));
  94. static int dodial_dial        __ARGS((int argc, char *argv[], void *p));
  95. static int dodial_init        __ARGS((int argc, char *argv[], void *p));
  96. static int dodial_send        __ARGS((int argc, char *argv[], void *p));
  97. static int dodial_speed        __ARGS((int argc, char *argv[], void *p));
  98. static int dodial_status    __ARGS((int argc, char *argv[], void *p));
  99. static int dodial_wait        __ARGS((int argc, char *argv[], void *p));
  100. static int dodial_cwait        __ARGS((int argc, char *argv[], void *p));
  101.  
  102. static int __stdargs dodialer        __ARGS((int argc, char *argv[], void *p));
  103. static int __stdargs do_inline    __ARGS((int argc, char *argv[], void *p));
  104.  
  105. static void add_cmd __ARGS((ITEM **hdr, ITEM **ptr, char *buf));
  106. static char *next_cmd __ARGS((char *buf, ITEM **ptr));
  107. static void clean_up __ARGS((void));
  108. static void clean __ARGS((ITEM **hdr));
  109. static int internal_send __ARGS((char *ptr, void *p));
  110. static int asy_kb_poll __ARGS((int dev));
  111.  
  112. static struct cmds dial_cmds[] =
  113.     {
  114.     { "control",     dodial_control,     0, 2, "control up | down" },
  115.     { "dial",        dodial_dial,        0, 0, "dial" },
  116.     { "init",        dodial_init,        0, 0, "init" },
  117.     { "send",         dodial_send,     0, 2, 
  118.     "send \"string\" [<milliseconds>]" }, 
  119.     { "speed",     dodial_speed,     0, 2, "speed <bps>" }, 
  120.     { "status",     dodial_status, 0, 2, "status up | down" }, 
  121.     { "wait",         dodial_wait,     0, 2, 
  122.     "wait <milliseconds> [ \"string\" [speed] ]" }, 
  123.     { "cwait",         dodial_cwait,     0, 2, 
  124.     "cwait <milliseconds> [ \"success string\" \"failure string\" [, \"failure string\" ...] [speed] ]" }, 
  125.     { NULLCHAR,     NULLFP,         0, 0, "Unknown command" }, 
  126.     };
  127.  
  128. static struct cmds cfg_cmds[] =
  129.     {
  130.     { "init",        cfg_init,            0, 2, "init \"string\"" },
  131.     { "dial_cmd",    cfg_dial_cmd,        0, 2, "dial_cmd \"string\"" },
  132.     { "ld_code",    cfg_ld_code,        0, 2, "ld_code \"string\"" },
  133.     { "number",    cfg_number,            0, 2, "number \"string\"" },
  134.     { "retries",    cfg_retries,        0, 2, "retries <count>" },
  135.     { NULLCHAR,     NULLFP,         0, 0, "Unknown command" }, 
  136.     };
  137.  
  138. static char cfg_intro[] = "configure:";
  139. static char exe_intro[] = "execute:";
  140. static int configuring = 0;                /* nz - found configuration section    */
  141.     
  142. static char *init = NULL;                /* initialization string            */
  143. static char *dial_cmd = NULL;            /* modem dial command                */
  144. static char *ld_code = NULL;            /* long distance code                */
  145. static ITEM *number = NULL;                /* telephone numbers                */
  146. static ITEM *nr_ptr = NULL;                /* -> current number                */
  147. static unsigned retries = 1;            /* number of dial retries            */
  148. static ITEM *cfg_cmd = NULL;            /* configuration commands            */
  149. static ITEM *exe_cmd = NULL;            /* script commands                    */
  150. static ITEM *cmd_ptr = NULL;            /* -> current script command        */
  151.  
  152. static int dial_inline = 0;                /* nz - dial inline                    */
  153. static int interrupted;                    /* nz - dial interrupted            */
  154.  
  155.  
  156. /****************************************************************************
  157. *    do_inline                                                                *
  158. *    Toggles the "inline dialing" flag and sets and resets the dialer task's    *
  159. *    stack size.                                                                *
  160. ****************************************************************************/
  161.  
  162. #ifndef ATARI
  163. #define    DIALER_STACK    512
  164. #else
  165. #define  DIALER_STACK   2512
  166. #endif
  167.  
  168. int __stdargs do_inline (argc, argv, p)
  169. int argc;
  170. char *argv[];
  171. void *p;
  172.     {
  173.     int rc;                                    /* return value                    */
  174.     struct cmds *cmd_ptr;                    /* -> command structure            */
  175.     
  176.     /* Set / reset / report flag value. */
  177.     
  178.     rc = setbool (&dial_inline, "Inline dialing", argc, argv);
  179.  
  180.     /* Set the dialer stack size. */
  181.  
  182.     cmd_ptr = Cmds;
  183.     while (cmd_ptr->name != NULLCHAR)
  184.         {
  185.         if (strcmp (cmd_ptr->name, "dialer") == 0)
  186.             break;
  187.  
  188.         cmd_ptr++;
  189.         }
  190.         
  191.     if (dial_inline == 0)
  192.         cmd_ptr->stksize = DIALER_STACK;    /* asynch process                */
  193.     else
  194.         cmd_ptr->stksize = 0;                /* inline process                */
  195.  
  196.     return (rc);
  197.     }    /* int do_inline (argc, argv, p) */
  198.     
  199.         
  200. /* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
  201.  *    <iface>        must be asy type
  202.  *    <filename>    contains commands which are executed.
  203.  *            missing: kill outstanding dialer.
  204.  *    <seconds>    interval to check for activity on <iface>.
  205.  *                (if 0 then demand dial)
  206.  *    <pings>     number of missed pings before redial.
  207.  *    <hostid>    interface to ping.
  208.  */
  209.  
  210. int __stdargs dodialer (argc, argv, p)
  211. int argc;
  212. char *argv[];
  213. void *p;
  214.     {
  215.     struct iface *ifp;
  216.     struct asy *ap;
  217.     int32 interval = 0L;        /* in seconds */
  218.     int32 last_wait = 0L;
  219.     int32 target = 0L;
  220.     int pings = 0;
  221.     int countdown;
  222.     char *filename;
  223.     char *ifn;
  224.     int result;
  225.     int s;
  226.     int exit_on_fail;
  227.  
  228.     if ((ifp = if_lookup (argv[1])) == NULLIF)
  229.         {
  230.         tprintf ("Interface %s unknown\n", argv[1]);
  231.         return 1;
  232.         }
  233.         
  234.     if (ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp)
  235.         {
  236.         tprintf ("Interface %s not asy port\n", argv[1]);
  237.         return 1;
  238.         }
  239.  
  240.     if (ifp->supv != NULLPROC)
  241.         {
  242.         while (ifp->supv != NULLPROC)
  243.             {
  244.             alert (ifp->supv, EABORT);
  245.             pwait (NULL);
  246.             }
  247.             
  248.         tprintf ("dialer terminated on %s\n", argv[1]);
  249.         }
  250.  
  251.     if (argc < 3)
  252.         {
  253.         /* just terminating */
  254.         return 0;
  255.         }
  256.  
  257.     chname (Curproc, ifn = if_name (ifp, " dialer"));
  258.     free (ifn);
  259. #ifdef ATARI
  260.     if (!access(argv[2], 0))                                /* check if file exists    */
  261.         filename = argv[2];
  262.     else
  263. #endif
  264.     filename = rootdircat (argv[2]);
  265.  
  266.     ap = &Asy[ ifp->dev ];
  267.  
  268.     if (argc == 4 && strcmp(argv[3], "failexit") == 0)
  269.         exit_on_fail = 1;
  270.     else exit_on_fail = 0;
  271.  
  272.     /* handle minimal command (just thru filename) */
  273.     
  274.     if (argc < 4 || exit_on_fail)
  275.         {
  276.         /* just dialing */
  277.         ifp->supv = Curproc;                /* so that it can be cancelled    */
  278.         result = redial (ifp, filename);
  279.  
  280.         if (filename != argv[2])
  281.             free (filename);
  282.  
  283.         ifp->supv = NULLPROC;
  284.         
  285.         if (result != 0 && exit_on_fail == 1)
  286.             doexit (0, NULL, NULL);
  287.  
  288.         return result;
  289.         }
  290.     /* get polling interval (arg 3) */
  291.     else if (strcmp(argv[3], "demand")
  292.             && (interval = atol (argv[3])) <= MIN_INTERVAL)
  293.         {
  294.         tprintf ("interval must be > %d seconds\n", MIN_INTERVAL);
  295.         return 1;
  296.         }
  297.  
  298.     if (strcmp(argv[3], "demand") == 0)
  299.         /* Interval of 0, so we're demand dialing */
  300.         {
  301.         int32 backoff;
  302.         tprintf("Demand dialing enabled\n");
  303.         backoff = 4;
  304.         ifp->supv = Curproc;                /* so that it can be cancelled    */
  305.         ifp->dial_me = 0;
  306.         while (!main_exit)
  307.             {
  308.             alarm (2000L);
  309.             if (pwait (& (ifp->supv)) == EABORT)
  310.                 break;
  311.             alarm (0L);
  312.             if (ifp->dial_me)
  313.                 {
  314.                 if (ap->dtr_usage == FOUND_DOWN ||
  315.                     ap->dtr_usage == MOVED_DOWN ||
  316.                     ap->rlsd_line_control == MOVED_DOWN)
  317.                     /* dial has been requested _and_ the link is down */
  318.                     {    
  319.                     tprintf("About to dial\n");
  320.                     if (redial (ifp, filename) == 0) {
  321.                         tprintf("Dial succeeded\n");
  322.                         backoff = 4;
  323.                         }
  324.                     else {
  325.                         if (backoff < 90000L) /* Max backoff is day & a bit */
  326.                             backoff = backoff * 2;
  327.                         tprintf("Dial failed, backing off for %lu seconds\n",
  328.                                                                     backoff);
  329.                         }
  330.                     }
  331.                 alarm (backoff * 1000L);
  332.                 if (pwait (& (ifp->supv)) == EABORT)
  333.                     break;
  334.                 alarm (0L);
  335.                 ifp->dial_me = 0;
  336.                 }
  337.             }
  338.         ifp->supv = NULLPROC;
  339.         tprintf("Demand dialing finished\n");
  340.         return 0;
  341.         }
  342.  
  343.     /* get the number of pings before redialing (arg 4) */
  344.  
  345.     if (argc < 5)
  346.         {
  347.         }
  348.     else if ((pings = atoi (argv[4])) <= 0)
  349.         {
  350.         tprintf ("pings must be > 0\n");
  351.         return 1;
  352.         }
  353.  
  354.     /* retrieve the host name (arg 5) */
  355.  
  356.     if (argc < 6)
  357.         {
  358.         }
  359.     else if ((target = resolve (argv[5])) == 0L)
  360.         {
  361.         tprintf (Badhost, argv[5]);
  362.         return 1;
  363.         }
  364.  
  365.     countdown = pings;
  366.     ifp->supv = Curproc;
  367.  
  368.     while (!main_exit)
  369.         {
  370.         int32 wait_for = interval;
  371.  
  372.         if (ap->dtr_usage == FOUND_DOWN ||
  373.             ap->dtr_usage == MOVED_DOWN ||
  374.             ap->rlsd_line_control == MOVED_DOWN)
  375.             {
  376.             /* definitely down */
  377.  
  378.             if (redial (ifp, filename) < 0)
  379.                 break;
  380.  
  381.             }
  382.         else if (ifp->lastrecv >= last_wait)
  383.             {
  384.             /* got something recently */
  385.  
  386.             wait_for -= secclock () - ifp->lastrecv;
  387.             countdown = pings;
  388.             }
  389.         else if (countdown < 1)
  390.             {
  391.             /* we're down, or host we ping is down */
  392.  
  393.             if (redial (ifp, filename) < 0)
  394.                 break;
  395.  
  396.             countdown = pings;
  397.             }
  398.         else if (target != 0L &&
  399.                 (s = socket (AF_INET, SOCK_RAW, ICMP_PTCL)) != -1)
  400.             {
  401.             pingem (s, target, 0, (int16)s, 0);
  402.             close_s (s);
  403.             countdown--;
  404.             }
  405.         else if (ifp->echo != NULLFP)
  406.             {
  407.             (*ifp->echo) (ifp, NULLBUF);
  408.             countdown--;
  409.             }
  410.  
  411.         last_wait = secclock ();
  412.         if (wait_for != 0L)
  413.             {
  414.             alarm (wait_for * 1000L);
  415.             if (pwait (& (ifp->supv)) == EABORT)
  416.                 break;
  417.  
  418.             alarm (0L);        /* clear alarm */
  419.             }
  420.             
  421.         }    /* while (!main_exit) */
  422.  
  423.     if (filename != argv[2])
  424.         free (filename);
  425.  
  426.     ifp->supv = NULLPROC;    /* We're being terminated */
  427.     return 0;
  428.     }    /* int dodialer (argc, argv, p) */
  429.  
  430.  
  431. /* execute dialer commands
  432.  * returns: -1 fatal error, 0 OK, 1 try again
  433.  */
  434.  
  435. static int redial (ifp, file)
  436. struct iface *ifp;
  437. char *file;
  438.     {
  439.     char *inbuf, *intmp;
  440.     FILE *fp;
  441.     int (*rawsave) __ARGS ((struct iface *, struct mbuf *));
  442.     struct session *sp;
  443.     int result = 0;
  444.     int save_input = Curproc->input;
  445.     int save_output = Curproc->output;
  446.     unsigned i;                            /* loop counter                        */
  447.  
  448.     if ((fp = fopen (file, READ_TEXT)) == NULLFILE)
  449.         {
  450.         tprintf ("redial: can't read %s\n", file);
  451.         return -1;    /* Causes dialer proc to terminate */
  452.         }
  453.         
  454.     /* Save output handler and temporarily redirect output to null */
  455.  
  456.     if (ifp->raw == bitbucket)
  457.         {
  458.         tprintf ("redial: tip or dialer already active on %s\n", ifp->name);
  459.         (void) fclose (fp);
  460.         return -1;
  461.         }
  462.  
  463.     /* allocate a session descriptor */
  464.  
  465.     if (dial_inline == 0)
  466.         {
  467.         if ((sp = newsession (ifp->name, DIAL)) == NULLSESSION)
  468.             {
  469.             tprintf ("Too many sessions\n");
  470.             (void) fclose (fp);
  471.             return 1;
  472.             }
  473.  
  474.         }
  475.         
  476.     tprintf ("Dialing on %s\n\n", ifp->name);
  477.  
  478.     /* Save output handler and temporarily redirect output to null */
  479.     
  480.     rawsave = ifp->raw;
  481.     ifp->raw = bitbucket;
  482.  
  483.     /* Suspend the packet input driver. Note that the transmit driver
  484.      * is left running since we use it to send buffers to the line.
  485.      */
  486.      
  487.     suspend (ifp->rxproc);
  488.  
  489. #ifdef notdef
  490.     tprintf ("rlsd: 0x%02x, dtr: 0x%02x\n", 
  491.              Asy[ifp->dev].rlsd_line_control, 
  492.              Asy[ifp->dev].dtr_usage);
  493. #endif
  494.  
  495.     inbuf = mallocw (BUFSIZ);
  496.  
  497.     /* Read the file into cfg_cmd and exe_cmd. */
  498.  
  499.     cfg_cmd = NULL;
  500.     exe_cmd = NULL;
  501.     cmd_ptr = cfg_cmd;                    /* initialize list pointer            */
  502.     configuring = 0;                    /* not configuring yet                */
  503.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  504.         {
  505.         if (strnicmp (inbuf, cfg_intro, strlen (cfg_intro)) == 0)
  506.             {
  507.             configuring = 1;            /* found config section                */
  508.             break;
  509.             }
  510.  
  511.         }
  512.  
  513.     if (configuring == 0)
  514.         {
  515.         tprintf ("redial: no \"configure:\" section\n");
  516.         (void) fclose (fp);
  517.         free (inbuf);
  518.         ifp->raw = rawsave;
  519.         resume (ifp->rxproc);
  520.         tprintf ("\nDial %s complete\n", ifp->name);
  521.  
  522.         /* Wait for awhile, so the user can read the screen. */
  523. #ifndef ATARI
  524.         Pause (10000L);
  525. #endif
  526.         if (dial_inline == 0)
  527.             {
  528.             freesession (sp);
  529.             }
  530.             
  531.         Curproc->input = save_input;
  532.         Curproc->output = save_output;
  533.         return (-1);
  534.         }
  535.  
  536.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  537.         {
  538.         if (strnicmp (inbuf, exe_intro, strlen (exe_intro)) == 0)
  539.             {
  540.             configuring = 0;            /* found execute section            */
  541.             break;
  542.             }
  543.  
  544.         if (*inbuf != '#' && *inbuf != '\n')
  545.             add_cmd (&cfg_cmd, &cmd_ptr, inbuf);    /* add to list            */
  546.  
  547.         }
  548.  
  549.     if (configuring == 1)
  550.         {
  551.         tprintf ("redial: no \"execute:\" section\n");
  552.         clean_up ();                    /* free list                        */
  553.         (void) fclose (fp);
  554.         free (inbuf);
  555.         ifp->raw = rawsave;
  556.         resume (ifp->rxproc);
  557.         tprintf ("\nDial %s complete\n", ifp->name);
  558.  
  559.         /* Wait for awhile, so the user can read the screen. */
  560. #ifndef ATARI     
  561.         Pause (10000L);
  562. #endif
  563.         if (dial_inline == 0)
  564.             {
  565.             freesession (sp);
  566.             }
  567.             
  568.         Curproc->input = save_input;
  569.         Curproc->output = save_output;
  570.         return (-1);
  571.         }
  572.  
  573.     cmd_ptr = exe_cmd;                    /* read in execute commands            */
  574.     while (fgets (inbuf, BUFSIZ, fp) != NULLCHAR)
  575.         {
  576.         if (*inbuf != '#' && *inbuf != '\n')
  577.             add_cmd (&exe_cmd, &cmd_ptr, inbuf);    /* add to list            */
  578.  
  579.         }
  580.  
  581.     (void) fclose (fp);
  582.     intmp = mallocw (BUFSIZ);
  583.  
  584.     /* Do the configure commands. */
  585.  
  586.     cmd_ptr = cfg_cmd;
  587.     while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR)
  588.         {
  589.         strcpy (intmp, inbuf);
  590.         rip (intmp);
  591.         log (-1, "%s dialer: %s", ifp->name, intmp);
  592.         if ((result = cmdparse (cfg_cmds, inbuf, ifp)) != 0)
  593.             {
  594.             tprintf ("\ninput line: %s\n", intmp);
  595.             break;
  596.             }
  597.             
  598.         }    /* while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR) */
  599.  
  600.     /* Do the execute commands. */
  601.  
  602.     nr_ptr = number;                    /* initialize number pointer        */
  603.     if (result == 0)
  604.         {
  605.         interrupted = 0;
  606.         for (i = 0; i < retries; i++)
  607.             {
  608.             if (pwait (NULL) == EABORT)
  609.                 break;                        /* we are being killed            */
  610.  
  611.             cmd_ptr = exe_cmd;
  612.             while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR)
  613.                 {
  614.                 int c;                        /* input character                */
  615.                 
  616.                 /* Poll the keyboard for 1/10 of a second to
  617.                  * see if <ESC> has been pressed.
  618.                  */
  619.  
  620.                 if (dial_inline != 0)
  621.                     {
  622.                     alarm (100L);
  623.                     if ((c = recvchar (Curproc->input)) != EOF)
  624.                         {
  625.                         alarm (0L);
  626.                         recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0);
  627.                         if (c == 0x01b)
  628.                             {
  629.                             /* <ESC> pressed - give up. */
  630.                             
  631.                             interrupted = 1;
  632.                             result = -1;
  633.                             tprintf ("interrupted\n");
  634.                             break;
  635.                             }
  636.  
  637.                         }
  638.  
  639.                     alarm (0L);
  640.                     }    /* if (dial_inline != 0) */
  641.  
  642.                 /* Process script command. */
  643.                 
  644.                 strcpy (intmp, inbuf);
  645.                 rip (intmp);
  646.                 log (-1, "%s dialer: %s", ifp->name, intmp);
  647.                 if ((result = cmdparse (dial_cmds, inbuf, ifp)) != 0)
  648.                     {
  649.                     tprintf ("\ninput line: %s\n", intmp);
  650.                     break;
  651.                     }
  652.             
  653.                 }    /* while (next_cmd (inbuf, &cmd_ptr) != NULLCHAR) */
  654.  
  655.             if (result == 0 || interrupted != 0)
  656.                 break;                    /* dial succeeded                    */
  657.  
  658.             }    /* for (i = 0; i < retries; i++) */
  659.  
  660.         }    /* if (result == 0) */
  661.  
  662.     clean_up ();                        /* free lists                        */
  663.     free (inbuf);
  664.     free (intmp);
  665.  
  666.     if (result == 0)
  667.         {
  668.         ifp->lastsent = ifp->lastrecv = secclock ();
  669.         }
  670.  
  671.     ifp->raw = rawsave;
  672.     resume (ifp->rxproc);
  673.     tprintf ("\nDial %s complete\n", ifp->name);
  674.  
  675.     /* Wait for awhile, so the user can read the screen, 
  676.      * AND to give it time to send some packets on the new connection!
  677.      */
  678. #ifndef ATARI
  679.     Pause (10000L);
  680. #endif
  681.     if (dial_inline == 0)
  682.         {
  683.         freesession (sp);
  684.         }
  685.         
  686.     Curproc->input = save_input;
  687.     Curproc->output = save_output;
  688.     return result;
  689.     }    /* static int redial (ifp, file) */
  690.  
  691.  
  692. static int dodial_control (argc, argv, p)
  693. int argc;
  694. char *argv[];
  695. void *p;
  696.     {
  697.     struct iface *ifp = p;
  698.     int param;
  699.  
  700.     if (ifp->ioctl == NULL)
  701.         return -1;
  702.  
  703.     if ((param = devparam (argv[1])) == -1)
  704.         return -1;
  705.  
  706.     (*ifp->ioctl) (ifp, param, TRUE, atol (argv[2]));
  707.     return 0;
  708.     }    /* static int dodial_control (argc, argv, p) */
  709.  
  710.  
  711. static int dodial_send (argc, argv, p)
  712. int argc;
  713. char *argv[];
  714. void *p;
  715.     {
  716.     struct iface *ifp = p;
  717.     struct mbuf *bp;
  718.  
  719.     if (argc > 2)
  720.         {
  721.         /* Send characters with inter-character delay
  722.          * (for dealing with prehistoric Micom switches that
  723.          * can't take back-to-back characters...yes, they
  724.          * still exist.)
  725.          */
  726.          
  727.         char *cp;
  728.         int32 cdelay = atol (argv[2]);
  729.  
  730.         for (cp = argv[1];*cp != '\0';cp++)
  731.             {
  732.             bp = qdata (cp, 1);
  733.             asy_send (ifp->dev, bp);
  734.             Pause (cdelay);
  735.             }
  736.             
  737.         }
  738.     else
  739.         {
  740.         bp = qdata (argv[1], strlen (argv[1]));
  741.         if (ifp->trace & IF_TRACE_RAW)
  742.             raw_dump (ifp, IF_TRACE_OUT, bp);
  743.             
  744.         asy_send (ifp->dev, bp);
  745.         }
  746.         
  747.     return 0;
  748.     }    /* static int dodial_send (argc, argv, p) */
  749.  
  750.  
  751. static int dodial_speed (argc, argv, p)
  752. int argc;
  753. char *argv[];
  754. void *p;
  755.     {
  756.     struct iface *ifp = p;
  757.  
  758.     if (argc < 2)
  759.         {
  760.         tprintf ("current speed = %u bps\n", Asy[ifp->dev].speed);
  761.         return 0;
  762.         }
  763.         
  764.     return asy_speed (ifp->dev, (int16) atol (argv[1]));
  765.     }    /* static int dodial_speed (argc, argv, p) */
  766.  
  767.  
  768. /*
  769.     dodial_status - Bring interface up or down
  770. */
  771.     
  772. static int dodial_status (int argc, char *argv[], void *p)
  773. {
  774.     struct iface *ifp = p;
  775.     int param;
  776.  
  777.     if (ifp->iostatus == NULL)
  778.         return -1;
  779.  
  780.     if ((param = devparam (argv[1])) == -1)
  781.         return -1;
  782.  
  783. /*    (*ifp->iostatus) (ifp, param, atol (argv[2]));  produces crash? */
  784.         
  785.     (*ifp->iostatus) (ifp, param, 0);
  786.  
  787.     return 0;
  788. }
  789.  
  790.  
  791. static int dodial_wait (argc, argv, p)
  792. int argc;
  793. char *argv[];
  794. void *p;
  795.     {
  796.     struct iface *ifp = p;
  797.     register int c = -1;
  798.  
  799.     alarm (atol (argv[1]));
  800.  
  801.     if (argc == 2)
  802.         {
  803.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  804.             {
  805.             tputc (c &= 0x7F);
  806.             tflush ();
  807.             }
  808.  
  809.         alarm (0L);
  810.         return 0;
  811.         }
  812.     else
  813.         {
  814.         register char *cp = argv[2];
  815.  
  816.         while (*cp != '\0' && (c = asy_kb_poll (ifp->dev)) != -1)
  817.             {
  818.             tputc (c &= 0x7F);
  819.             tflush ();
  820.  
  821.             if (*cp++ != c)
  822.                 {
  823.                 cp = argv[2];
  824.                 }
  825.                 
  826.             }    /* while (*cp != '\0' && (c = asy_kb_poll (ifp->dev)) != -1) */
  827.  
  828.         if (argc > 3)
  829.             {
  830.             if (stricmp (argv[3], "speed") == 0)
  831.                 {
  832.                 int16 speed = 0;
  833.  
  834.                 while ((c = asy_kb_poll (ifp->dev)) != -1)
  835.                     {
  836.                     tputc (c &= 0x7F);
  837.                     tflush ();
  838.  
  839.                     if (isdigit (c))
  840.                         {
  841.                         speed *= 10;
  842.                         speed += c - '0';
  843.                         }
  844.                     else
  845.                         {
  846.                         alarm (0L);
  847.                         return asy_speed (ifp->dev, speed);
  848.                         }
  849.                         
  850.                     }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  851.                     
  852.                 }    /* if (stricmp (argv[3], "speed") == 0) */
  853.             else
  854.                 {
  855.                 return -1;
  856.                 }
  857.                 
  858.             }    /* if (argc > 3) */
  859.             
  860.         }    /* if (argc != 2) */
  861.         
  862.     alarm (0L);
  863.     return (c == -1);
  864.     }    /* static int dodial_wait (argc, argv, p) */
  865.  
  866.  
  867. /****************************************************************************
  868. *    cfg_init                                                                *
  869. *    Sets up the modem initialization string.                                *
  870. ****************************************************************************/
  871.  
  872. static int cfg_init (argc, argv, p)
  873. int argc;
  874. char **argv;
  875. void *p;
  876.     {
  877.     if (init != NULL)
  878.         free (init);
  879.  
  880.     if (strlen (argv[1]) == 0)
  881.         {
  882.         init = NULL;
  883.         return (0);
  884.         }
  885.         
  886.     init = mallocw (strlen (argv[1]) + 1);
  887.     (void) strcpy (init, argv[1]);
  888.     return (0);
  889.     }    /* static int cfg_init (argc, argv, p) */
  890.  
  891.  
  892. /****************************************************************************
  893. *    cfg_dial_cmd                                                            *
  894. *    Sets up the modem dial command.                                            *
  895. ****************************************************************************/
  896.  
  897. static int cfg_dial_cmd (argc, argv, p)
  898. int argc;
  899. char **argv;
  900. void *p;
  901.     {
  902.     if (dial_cmd != NULL)
  903.         free (dial_cmd);
  904.         
  905.     if (strlen (argv[1]) == 0)
  906.         {
  907.         dial_cmd = NULL;
  908.         return (0);
  909.         }
  910.         
  911.     dial_cmd = mallocw (strlen (argv[1]) + 1);
  912.     (void) strcpy (dial_cmd, argv[1]);
  913.     return (0);
  914.     }    /* static int cfg_dial_cmd (argc, argv, p) */
  915.  
  916.  
  917. /****************************************************************************
  918. *    cfg_ld_code                                                                *
  919. *    Sets up the long distance code.                                            *
  920. ****************************************************************************/
  921.  
  922. static int cfg_ld_code (argc, argv, p)
  923. int argc;
  924. char **argv;
  925. void *p;
  926.     {
  927.     if (ld_code != NULL)
  928.         free (ld_code);
  929.         
  930.     if (strlen (argv[1]) == 0)
  931.         {
  932.         ld_code = NULL;
  933.         return (0);
  934.         }
  935.         
  936.     ld_code = mallocw (strlen (argv[1]) + 1);
  937.     (void) strcpy (ld_code, argv[1]);
  938.     return (0);
  939.     }    /* static int cfg_ld_code (argc, argv, p) */
  940.  
  941.  
  942. /****************************************************************************
  943. *    cfg_retries                                                                *
  944. *    Sets up the number of dial retries.                                        *
  945. ****************************************************************************/
  946.  
  947. static int cfg_retries (argc, argv, p)
  948. int argc;
  949. char **argv;
  950. void *p;
  951.     {
  952.     (void) sscanf (argv[1], "%u", &retries);
  953.     if (retries <= 0)
  954.         return (-1);                    /* must be >= 1                        */
  955.  
  956.     return (0);
  957.     }    /* static int cfg_retries (argc, argv, p) */
  958.  
  959.  
  960. /****************************************************************************
  961. *    cfg_number                                                                *
  962. *    Adds a number to the dial list.                                            *
  963. ****************************************************************************/
  964.  
  965. static int cfg_number (argc, argv, p)
  966. int argc;
  967. char **argv;
  968. void *p;
  969.     {
  970.     add_cmd (&number, &nr_ptr, argv[1]);
  971.     return (0);
  972.     }    /* static int cfg_number (argc, argv, p) */
  973.  
  974.  
  975. /****************************************************************************
  976. *    internal_send                                                            *
  977. *    Sends a string to dodial_send ().                                        *
  978. ****************************************************************************/
  979.  
  980. static int internal_send (ptr, p)
  981. char *ptr;
  982. void *p;
  983.     {
  984.     char *argv[2];
  985.  
  986.     argv[0] = NULL;
  987.     argv[1] = ptr;
  988.     return (dodial_send (2, argv, p));
  989.     }    /* static int internal_send (ptr, p) */
  990.     
  991.  
  992. /****************************************************************************
  993. *    dodial_init                                                                *
  994. *    Send the initialisation string to the modem.                            *
  995. ****************************************************************************/
  996.  
  997. static int dodial_init (argc, argv, p)
  998. int argc;
  999. char **argv;
  1000. void *p;
  1001.     {
  1002.     if (init == NULL)
  1003.         return (0);                        /* no initialization string - ok    */
  1004.  
  1005.     return (internal_send (init, p));
  1006.     }    /* static int dodial_init (argc, argv, p) */
  1007.  
  1008.  
  1009. /****************************************************************************
  1010. *    dodial_dial                                                                *
  1011. *    Send the dialer commands and the next number to the modem.                *
  1012. ****************************************************************************/
  1013.  
  1014. static int dodial_dial (argc, argv, p)
  1015. int argc;
  1016. char **argv;
  1017. void *p;
  1018.     {
  1019.     char *buf;                            /* -> number buffer                    */
  1020.     int rc;                                /* result code                        */
  1021.  
  1022.     if (number == NULL)
  1023.         return (-1);                    /* no numbers specified                */
  1024.         
  1025.     buf = mallocw (BUFSIZ);                /* get a buffer for the number        */
  1026.     if (dial_cmd != NULL)
  1027.         {
  1028.         /* Send the dial command. */
  1029.         
  1030.         if ((rc = internal_send (dial_cmd, p)) != 0)
  1031.             {
  1032.             free (buf);
  1033.             return (rc);
  1034.             }
  1035.  
  1036.         }    /* if (dial_cmd != NULL) */
  1037.  
  1038.     if (ld_code != NULL)
  1039.         {
  1040.         /* Send the long distance code. */
  1041.         
  1042.         if ((rc = internal_send (ld_code, p)) != 0)
  1043.             {
  1044.             free (buf);
  1045.             return (rc);
  1046.             }
  1047.  
  1048.         }    /* if (ld_code != NULL) */
  1049.  
  1050.     /* Send the next number. */
  1051.  
  1052.     if (next_cmd (buf, &nr_ptr) == NULLCHAR)
  1053.         {
  1054.         /* Try resetting the pointer. */
  1055.  
  1056.         nr_ptr = number;
  1057.         if (next_cmd (buf, &nr_ptr) == NULLCHAR)
  1058.             {
  1059.             free (buf);                    /* gone badly wrong                    */
  1060.             return (-1);
  1061.             }
  1062.  
  1063.         }    /* if (next_cmd (buf, nr_ptr) == NULLCHAR) */
  1064.  
  1065.     if ((rc = internal_send (buf, p)) != 0)    /* send the number                */
  1066.         {
  1067.         free (buf);
  1068.         return (rc);
  1069.         }
  1070.  
  1071.     rc = internal_send ("\r", p);
  1072.     free (buf);
  1073.     return (rc);
  1074.     }    /* static int dodial_dial (argc, argv, p) */
  1075.  
  1076.  
  1077. /****************************************************************************
  1078. *    dodial_cwait                                                            *
  1079. *    Conditional version of dodial_wait ().                                    *
  1080. ****************************************************************************/
  1081.  
  1082. static int dodial_cwait (argc, argv, p)
  1083. int argc;
  1084. char *argv[];
  1085. void *p;
  1086.     {
  1087.     struct iface *ifp = p;
  1088.     register int c = -1;
  1089.     int speedarg;                        /* index of "speed" argument        */
  1090.     int lastarg;                        /* index of last argument            */
  1091.     int i;                                /* loop counter                        */
  1092.     char failed;                        /* failure flag - nz means failed    */
  1093.     
  1094.     alarm (atol (argv[1]));
  1095.  
  1096.     lastarg = argc - 1;
  1097.     if (stricmp (argv[lastarg], "speed") == 0)
  1098.         {
  1099.         speedarg = lastarg;
  1100.         lastarg--;
  1101.         }
  1102.     else
  1103.         speedarg = 0;                    /* no "speed" argument                */
  1104.         
  1105.     if (argc == 2)
  1106.         {
  1107.         /* Wait for duration expiry only. */
  1108.         
  1109.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  1110.             {
  1111.             tputc (c &= 0x7F);
  1112.             tflush ();
  1113.             }
  1114.  
  1115.         alarm (0L);
  1116.         return 0;
  1117.         }
  1118.     else
  1119.         {
  1120.         register char *cp = argv[2];    /* -> success string                */
  1121.         char **fail_ptr;                /* array of ptrs to failure strings    */
  1122.  
  1123.         /* Set up the array of failure string pointers. */
  1124.  
  1125.         fail_ptr = (char **) mallocw ((lastarg - 2) * sizeof (char *));
  1126.         for (i = 0; i < (lastarg - 2); i++)
  1127.             fail_ptr[i] = argv[i + 3];
  1128.  
  1129.         /* Looking for string matches. */
  1130.  
  1131.         failed = 0;
  1132.         while ((c = asy_kb_poll (ifp->dev)) != -1)
  1133.             {
  1134.             tputc (c &= 0x7F);
  1135.             tflush ();
  1136.  
  1137.             /* Check the success string first. */
  1138.  
  1139.             if (*cp == '\0')
  1140.                 break;                    /* we got a connect                    */
  1141.                 
  1142.             if (*cp++ != c)
  1143.                 {
  1144.                 cp = argv[2];
  1145.                 }
  1146.  
  1147.             /* Now check the failure strings. */
  1148.  
  1149.             for (i = 0; i < (lastarg - 2); i++)
  1150.                 {
  1151.                 if (*fail_ptr[i] == '\0')
  1152.                     {
  1153.                     failed = 1;
  1154.                     break;                /* we lost                            */
  1155.                     }
  1156.  
  1157.                 if (*fail_ptr[i]++ != c)
  1158.                     {
  1159.                     fail_ptr[i] = argv[i + 3];
  1160.                     }
  1161.  
  1162.                 }
  1163.  
  1164.             if (failed)
  1165.                 break;
  1166.                 
  1167.             }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  1168.                 
  1169.         free (fail_ptr);                /* give back heap memory            */
  1170.         
  1171.         /* If we get here, we may have matched the "success" string. */
  1172.  
  1173.         if (*cp != '\0')
  1174.             {
  1175.             alarm (0L);
  1176.             return (-1);                /* we didn't                        */
  1177.             }
  1178.             
  1179.         if (speedarg != 0)
  1180.             {
  1181.             int16 speed = 0;
  1182.  
  1183.             while ((c = asy_kb_poll (ifp->dev)) != -1)
  1184.                 {
  1185.                 tputc (c &= 0x7F);
  1186.                 tflush ();
  1187.  
  1188.                 if (isdigit (c))
  1189.                     {
  1190.                     speed *= 10;
  1191.                     speed += c - '0';
  1192.                     }
  1193.                 else
  1194.                     {
  1195.                     alarm (0L);
  1196.                     return asy_speed (ifp->dev, speed);
  1197.                     }
  1198.                         
  1199.                 }    /* while ((c = asy_kb_poll (ifp->dev)) != -1) */
  1200.                     
  1201.             }    /* if (stricmp (lastarg, "speed") == 0) */
  1202.             
  1203.         }    /* if (argc != 2) */
  1204.         
  1205.     alarm (0L);
  1206.     return (c == -1);
  1207.     }    /* static int dodial_cwait (argc, argv, p) */
  1208.  
  1209.     
  1210. /****************************************************************************
  1211. *    add_cmd                                                                    *
  1212. *    Add a string to the end of the list whose header is pointed to by         *
  1213. *    <*hdr>.  <*ptr>    (if non-NULL) points to the last item in the list.        *
  1214. *    <buf> points to the data to be added to the list and is assumed to be    *
  1215. *    an ASCIIZ string.                                                        *
  1216. ****************************************************************************/
  1217.  
  1218. static void add_cmd (hdr, ptr, buf)
  1219. ITEM **hdr;
  1220. ITEM **ptr;
  1221. char *buf;
  1222.     {
  1223.     if (strlen (buf) == 0)
  1224.         return;
  1225.         
  1226.     if (*hdr == NULL)
  1227.         {
  1228.         /* Empty list. */
  1229.  
  1230.         *hdr = (ITEM *) mallocw (sizeof (ITEM));
  1231.         *ptr = *hdr;
  1232.         }
  1233.     else
  1234.         {
  1235.         (*ptr)->next = (ITEM *) mallocw (sizeof (ITEM));
  1236.         *ptr = (*ptr)->next;
  1237.         }
  1238.  
  1239.     (*ptr)->data = (char *) mallocw (strlen (buf) + 1);
  1240.     (*ptr)->next = NULL;
  1241.     (void) strcpy ((*ptr)->data, buf);
  1242.     }    /* static void add_cmd (hdr, ptr, buf) */
  1243.  
  1244.  
  1245. /****************************************************************************
  1246. *    next_cmd                                                                *
  1247. *    Copies the data part of the item pointed to by <*ptr> into the buffer    *
  1248. *    pointed to by <buf>.  This area is assumed to be large enough to hold    *
  1249. *    the data.  <*ptr> is advanced to point to the next item.  Returns <buf>    *
  1250. *    if there is another item, NULLCHAR at the end of the list.                *
  1251. ****************************************************************************/
  1252.     
  1253. static char *next_cmd (buf, ptr)
  1254. char *buf;
  1255. ITEM **ptr;
  1256.     {
  1257.     if (*ptr == NULL)
  1258.         return (NULLCHAR);
  1259.         
  1260.     (void) strcpy (buf, (*ptr)->data);
  1261.     *ptr = (*ptr)->next;
  1262.     return (buf);
  1263.     }    /* static char *next_cmd (buf, ptr) */
  1264.     
  1265.  
  1266. /****************************************************************************
  1267. *    clean_up                                                                *
  1268. *    Frees the heap memory used by the various lists.                        *
  1269. ****************************************************************************/
  1270.  
  1271. static void clean_up ()
  1272.     {
  1273.     clean (&number);
  1274.     clean (&cfg_cmd);
  1275.     clean (&exe_cmd);
  1276.     if (init != NULL)
  1277.         {
  1278.         free (init);
  1279.         init = NULL;
  1280.         }
  1281.  
  1282.     if (dial_cmd != NULL)
  1283.         {
  1284.         free (dial_cmd);
  1285.         dial_cmd = NULL;
  1286.         }
  1287.         
  1288.     if (ld_code != NULL)
  1289.         {
  1290.         free (ld_code);
  1291.         ld_code = NULL;
  1292.         }
  1293.  
  1294.     retries = 1;        
  1295.     }    /* static void clean_up () */
  1296.  
  1297.  
  1298. /****************************************************************************
  1299. *    clean                                                                    *
  1300. *    Free up the list pointed to by <*hdr>.                                    *
  1301. ****************************************************************************/
  1302.  
  1303. static void clean (hdr)
  1304. ITEM **hdr;
  1305.     {
  1306.     ITEM *p, *q;                        /* list followers                    */
  1307.  
  1308.     p = *hdr;
  1309.     while (p != NULL)
  1310.         {
  1311.         q = p->next;
  1312.         free (p->data);
  1313.         free (p);
  1314.         p = q;
  1315.         }
  1316.  
  1317.     *hdr = NULL;
  1318.     }    /* static void clean (hdr) */
  1319.  
  1320.  
  1321. /****************************************************************************
  1322. *    asy_kb_poll                                                                *
  1323. *    Polls the async interface for incoming characters and the keyboard for    *
  1324. *    <ESC>.  Returns the character on the async receive queue or -1 if timed    *
  1325. *    out or <ESC> detected.                                                    *
  1326. ****************************************************************************/
  1327.  
  1328. static int asy_kb_poll (dev)
  1329. int dev;
  1330.     {
  1331.     int c;                                /* input character                    */
  1332.  
  1333.     for (;;)
  1334.         {
  1335.         /* Check keyboard. */
  1336.         
  1337.         if (socklen (Curproc->input,0) > 0)
  1338.             {
  1339.             c = recvchar (Curproc->input);
  1340.             if (c != EOF)
  1341.                 {
  1342.                 recv_mbuf (Curproc->input, NULLBUFP, 0, NULLCHAR, 0);
  1343.                 if (c == 0x1b)
  1344.                     {
  1345.                     /* <ESC> pressed - give up. */
  1346.  
  1347.                     interrupted = 1;
  1348.                     c = -1;
  1349.                     break;
  1350.                     }
  1351.  
  1352.                 }    /* if (c != EOF) */
  1353.  
  1354.             }    /* if (socklen (Curproc->input,0) > 0) */
  1355.  
  1356.         /* Check async. */
  1357.  
  1358.         if (asy_len (dev) > 0)
  1359.             {
  1360.             c = get_asy (dev);
  1361.             break;
  1362.             }
  1363.  
  1364.         /* Let someone else run. */
  1365.  
  1366.         if (pwait (0) != 0)
  1367.             {
  1368.             c = -1;
  1369.             break;
  1370.             }
  1371.  
  1372.         }    /* for (;;) */
  1373.  
  1374.     return (c);
  1375.     }    /* static int asy_kb_poll (dev) */
  1376.